package at.jku.ssw.fortress.ui.assistant;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.CompletionProposal;
import org.eclipse.jface.text.contentassist.ContentAssistEvent;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.jface.text.contentassist.ICompletionListener;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;

import at.jku.ssw.fortress.ui.Macros;
import at.jku.ssw.fortress.ui.Macros.Macro;

public class CopyOfContentAssistProcessor implements IContentAssistProcessor, ICompletionListener {

	private static final String[] keywords = { "BIG", "SI", "unit", "absorbs", "abstract",
			"also", "api", "as", "asif", "at", "atomic", "bool", "case", "catch", "coerces",
			"coercion", "component", "comprises", "default", "dim", "do", "elif", "else",
			"end", "ensures", "except", "excludes", "exit", "export", "extends", "finally",
			"fn", "for", "forbid", "from", "getter", "hidden", "ident", "idiom", "if",
			"import", "in", "int", "invariant", "io", "juxtaposition", "label", "largest",
			"nat", "object", "of", "or", "opr", "private", "property", "provided", "requires",
			"self", "settable", "setter", "smallest", "spawn", "syntax", "test", "then",
			"throw", "throws", "trait", "transient", "try", "tryatomic", "type", "typecase",
			"unit", "value", "var", "where", "while", "widening", "widens", "with", "wrapped" };

	private Macros greek;

	private Macros brackets;

	private Macros unicode;

	private final ContentAssistant assistant;
	
	private ICompletionProposal[] keywordProposals;
	
	public CopyOfContentAssistProcessor(ContentAssistant assistant) {
		this.assistant = assistant;
		keywordProposals = new ICompletionProposal[keywords.length];
		for (int i = 0; i < keywords.length; i++) {
			keywordProposals[i] = new CompletionProposal(keywords[i],0,0,0);
		}
	}

	private void init() {
		if(greek == null) {
			greek = new Macros("greek.txt", false);
			brackets = new Macros("brackets.txt", false);
			unicode = new Macros("UnicodeData-4.0.0.txt", true);
		}
	}
	
	private String prefix(String code, int offset) {
		char[] c = code.toCharArray();
		int pos = offset - 1;
		while (pos >= 0 && Character.isJavaIdentifierPart(c[pos])) {
			pos--;
		}
		return code.substring(pos + 1, offset);
	}

	public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
		return null;
	}

	public char[] getCompletionProposalAutoActivationCharacters() {
		return null;
	}

	public char[] getContextInformationAutoActivationCharacters() {
		return null;
	}

	public IContextInformationValidator getContextInformationValidator() {
		return null;
	}

	public String getErrorMessage() {
		return null;
	}

	private static final int KEYWORDS = 0;

	private static final int GREEK = 1;

	private static final int BRACKETS = 2;

	private static final int UNICODE = 3;

	private static final int LAST = 4;

	private int mode = KEYWORDS;
	
	int lastOffset;
	
	private static final String[] modeString = { "KEYWORDS", "GREEK", "BRACKETS", "UNICODE" };
	
	public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
		init();
		if(lastOffset == offset) {
			mode = (mode + 1) % LAST;
		}
		List<ICompletionProposal> proposals = createProposals(keywords, viewer, offset);
		lastOffset = offset;
		started = false;
		assistant.setStatusMessage(modeString[mode] + " - Press 'Ctrl+Space' to show other proposals");
		return proposals.toArray(new ICompletionProposal[0]);
	}
	
	private List<ICompletionProposal> createProposals(String[] candidates, ITextViewer viewer,
			int offset) {
		Arrays.sort(candidates);
		List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
		String prefix = getPrefix(viewer.getDocument(), offset - 1);
		if (mode == KEYWORDS) {
			createKeywordProposals(candidates, offset, proposals, prefix);
			if (started && proposals.isEmpty()) {
				mode++;
				addProposals(greek, offset, proposals, prefix);
			}
			if (started && proposals.isEmpty()) {
				mode++;
				addProposals(brackets, offset, proposals, prefix);
			}
			if (started && proposals.isEmpty()) {
				mode++;
				addProposals(unicode, offset, proposals, prefix);
			}
		}
		if (mode == GREEK) {
			addProposals(greek, offset, proposals, prefix);
		}
		if (mode == BRACKETS) {
			addProposals(brackets, offset, proposals, prefix);
		}
		if (mode == UNICODE) {
			addProposals(unicode, offset, proposals, prefix);
		}
		
		return proposals;
	}

	private void createKeywordProposals(String[] candidates, int offset, List<ICompletionProposal> proposals, String prefix) {
		for (String kw : candidates) {
			if (prefix.length() <= kw.length()) {
				if (kw.substring(0, prefix.length()).equalsIgnoreCase(prefix)) {
					proposals.add(createProposal(kw, offset - prefix.length(), prefix
							.length()));
				}
			}
		}
	}

	private void addProposals(Macros m, int offset, List<ICompletionProposal> proposals,
			String prefix) {
		Macro[] cs = m.search(prefix);
		for (Macro c : cs) {
			proposals.add(createProposal(c, offset - prefix.length(), prefix.length()));
		}
	}

	private ICompletionProposal createProposal(Macro uc, int offset, int prefix) {
		String replace = uc.ascii == null || uc.ascii.equals("") ? uc.ch + "" : uc.ascii;
		CompletionProposal p = new CompletionProposal(replace, offset, prefix, replace
				.length(), null, replace + " - " + uc.name, null, null);
		return p;
	}

	private ICompletionProposal createProposal(String name, int offset, int prefix) {
		CompletionProposal p = new CompletionProposal(name, offset, prefix, name.length());
		return p;
	}

	private String getPrefix(IDocument doc, int offset) {
		int pos = offset;
		try {
			while (pos >= 0 && Character.isJavaIdentifierPart(doc.getChar(pos))) {
				pos--;
			}
			return doc.get(pos + 1, offset - pos);
		} catch (BadLocationException e) {
			e.printStackTrace();
		}
		return "";
	}

	public void assistSessionEnded(ContentAssistEvent event) {
	}
	
	boolean started;

	public void assistSessionStarted(ContentAssistEvent event) {
		System.out.println("started");
		mode = KEYWORDS;
		lastOffset = -1;
		started = true;
	}

	public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) {
	}

}
